#include "Vector3D.h"

namespace math_tools
{
	Vector3D &Vector3D::unit()
	{
		if (isDefault())
		{
			double rep = mag();

			if (rep < EPSILON)
			{
				_x = 0.0;
				_y = 0.0;
				_z = 0.0;
			}
			else
			{
				double temp = 1.0 / rep;
				_x *= temp;
				_y *= temp;
				_z *= temp;
			}
			_Status = UNIT;
		}
		return *this;
	}

	Vector3D &Vector3D::Default()
	{

		if (isUnit())

			_Status = DEFAULT;

		return *this;

	}

	Vector3D & Vector3D::invert(const Vector3D &v1, Vector3D &result)
	{

		if (v1.isValid())
		{
			result._x = -v1._x;
			result._y = -v1._y;
			result._z = -v1._z;
			result._Status = v1._Status;
		}
		else
			result = Vector3D();
		return result;
	}

	Vector3D &Vector3D::add(const Vector3D &v1, const Vector3D &v2,
			Vector3D &result)
	{

		if (v1.isValid() && v2.isValid())
		{
			result._x = v1._x + v2._x;
			result._y = v1._y + v2._y;
			result._z = v1._z + v2._z;
			result._Status = DEFAULT;
		}
		else
			result = Vector3D();

		return result;
	}

	Vector3D &Vector3D::subtract(const Vector3D &v1, const Vector3D &v2,
			Vector3D &result)
	{

		if (v1.isValid() && v2.isValid())
		{
			result._x = v1._x - v2._x;
			result._y = v1._y - v2._y;
			result._z = v1._z - v2._z;
			result._Status = DEFAULT;
		}
		else
			result = Vector3D();

		return result;
	}

	/// <summary>
	/// Vrati vektorovy sucin vektorov
	/// </summary>
	Vector3D &Vector3D::cross(const Vector3D &v1, const Vector3D &v2,
			Vector3D &result)
	{

		if (v1.isValid() && v2.isValid())
		{
			result._x = v1._y * v2._z - v1._z * v2._y;
			result._y = v1._z * v2._x - v1._x * v2._z;
			result._z = v1._x * v2._y - v1._y * v2._x;
			result._Status = DEFAULT;
		}
		else
			result = Vector3D();

		return result;
	}

	Vector3D &Vector3D::multiply(const Vector3D &v1, const double &scale,
			Vector3D &result)
	{

		if (v1.isValid())
		{
			result._x = v1._x * scale;
			result._y = v1._y * scale;
			result._z = v1._z * scale;
			result._Status = DEFAULT;
		}
		else
			result = Vector3D();

		return result;
	}

	ostream &Vector3D::write(ostream &out) const
	{
		if (isValid())
		{
			if (isUnit())
				return out << "<" << getX() << "," << getY() << "," << getZ()
						<< ">";
			else
				return out << "[" << getX() << "," << getY() << "," << getZ()
						<< "]";
		}

		return out << "Invalid";
	}

	istream &Vector3D::read(istream &in)
	{
		char buf[20], ch, ch2;
		in >> ch2;
		if (ch2 != 'I')
		{
			double x, y, z;
			in >> x >> ch >> y >> ch >> z;
			*this = Vector3D(x, y, z);
			if (ch2 == '<')
				unit();
		}
		else
		{
			*this = Vector3D();
			in.get(buf, 20, 'd');
		}

		return in >> ch;
	}
}
